/*
 * @Descripttion: 
 * @Author: zhangchong zc16607@gmail.com
 * @Date: 2023-05-23 16:19:42
 * @LastEditors: zhangchong zc16607@gmail.com
 * @LastEditTime: 2023-07-05 09:31:36
 */
import { ipcMain, shell, Notification } from "electron"
import childProcess from 'child_process'
import fs from 'fs'
import path, { resolve } from 'path'
import crypto from 'crypto'
import admZip from 'adm-zip'
import iconv from 'iconv-lite'

let tabWinObj = {}
const taskId = [] // 进程pid
const taskLog = {} // 进程日志
const taskProcess = {} // 进程进度
let _percent = 0
const percent = {
  get: () => _percent,
  set: (val) => {
    val > 99 ? _percent = 100 : _percent = val
    tabWinObj.win && tabWinObj.win.setProgressBar(parseInt(_percent) / 100, { mode: _percent === 100 ? 'none' : 'normal' })
    apiSend.percent(_percent)
  }
}

const apiInvoke = {
  getCurrentDir: async (event, args) => {
    const getDiskDirList = async () => {
      if (!args.length || !args[0]) {
        // 获取盘符
        const cmd = () => {
          return new Promise((resolve) => {
            childProcess.exec('wmic logicaldisk where drivetype=3 get deviceid', (err, stdout) => {
              if (err !== null) {
                console.error(err);
                return resolve()
              }
              let stdoutArr = [...stdout]
              let res = []
              stdoutArr.forEach((v, i) => {
                if (v === ':') {
                  res.push(stdoutArr[i - 1] + ':');
                }
              })
              return resolve(res)
            })
          })
        }
        const diskRes = await cmd()
        return diskRes
      } else {
        const folderPath = args[0]
        return typeof folderPath !== 'string' ? [] : fs.readdirSync(folderPath).filter(file => {
          try {
            return fs.statSync(path.join(folderPath, file)).isDirectory()
          } catch {
            return false
          }
        })
      }
    }
    return await getDiskDirList()
  },
  build: async (event, data) => {
    const buildStartTime = new Date().valueOf()
    // 编译和复制文件 生成一个cmd编译内容
    const buildConfig = data[0]
    const { env, rootDir } = buildConfig
    const envCmdMapping = { 'test': 'npm run build:stage', 'train': 'npm run build:train', 'prod': 'npm run build' }

    const ratio = 1 / buildConfig.project.length

    // 使用一个或多个子进程，执行cmd内容，生成进程[id]，放入buildTask
    // const randomFileName = `cmd-${process.pid}-` + crypto.randomBytes(16).toString('Hex')
    // const tmpDir = os.tmpdir()
    // const tempFilePath = path.join(tmpDir, `${randomFileName}.cmd`)

    percent.set(10)

    for (let i = 0; i < buildConfig.project.length; i++) {
      let currentProject = buildConfig.project[i]
      try {
        await execSingleBuild(ratio, envCmdMapping[env], path.join(rootDir, currentProject))
      } catch (e) { return }
    }

    // 复制打包后的文件
    for (let i = 0; i < buildConfig.project.length; i++) {
      let currentProject = buildConfig.project[i]
      let sourceDir = path.join(rootDir, currentProject)
      let distDir = path.join(buildConfig.outputDir, currentProject)
      await execSingleCopy(ratio, sourceDir, distDir)
    }

    let packagePath = path.join(buildConfig.outputDir, '/')

    // 执行打包操作（如果需要打包, 并且有进程[id]）(10%)
    if (buildConfig.compress) {
      apiSend.buildInfo('\n')
      apiSend.buildInfo(`--------------------------------压缩中--------------------------------`)
      apiSend.buildInfo('\n')
      apiSend.buildInfo('\n')
      apiSend.buildInfo('\n')
      const envPackMapping = { 'test': '测试环境', 'train': '培训环境', 'prod': '正式环境' }
      const now = new Date()
      const month = `${now.getMonth() + 1}`.length === 1 ? `0${now.getMonth() + 1}` : now.getMonth() + 1
      const day = `${now.getDate()}`.length === 1 ? `0${now.getDate()}` : now.getDate()
      const hour = `${now.getHours()}`.length === 1 ? `0${now.getHours()}` : now.getHours()
      const minute = `${now.getMinutes() + 1}`.length === 1 ? `0${now.getMinutes() + 1}` : now.getMinutes() + 1
      const packName = buildConfig.name + '-' + envPackMapping[env] + '-' + `${month}${day}${hour}${minute}`

      const zip = new admZip()

      const zipTask = []
      buildConfig.project.map(pro => {
        zipTask.push(zip.addLocalFolderPromise(path.join(buildConfig.outputDir, pro), { zipPath: pro }))
      })
      percent.set(percent.get() + 0.03 * 100)
      await Promise.all(zipTask)
      percent.set(percent.get() + 0.03 * 100)
      const pgpath = path.join(buildConfig.outputDir, `${packName}.zip`)
      packagePath = pgpath
      zip.writeZip(pgpath)
    }

    // 执行完毕，清除进程[id]
    const buildEndTime = new Date().valueOf()
    const diffTime = buildEndTime - buildStartTime
    // 将差值转换为分钟和秒
    const diffMinutes = Math.floor(diffTime / 1000 / 60)
    const diffSeconds = Math.floor((diffTime / 1000) % 60)
    apiSend.buildInfo(`--------------------------------打包完成！--------------------------------`)
    apiSend.buildInfo('\n')
    apiSend.buildInfo(`开始时间 ${new Date(buildStartTime).toLocaleString()}`)
    apiSend.buildInfo(`结束时间 ${new Date().toLocaleString()}`)
    apiSend.buildInfo(`用时${diffMinutes ? ' ' + diffMinutes + ' 分钟' : ''} ${diffSeconds} 秒`)
    apiSend.buildInfo('\n')
    apiSend.buildInfo('--------------------------------------------------------------------------')
    percent.set(100)

    // 打包后操作
    if (buildConfig.openDir) {
      // 打开文件夹
      if (buildConfig.compress) {
        // 显示压缩包 
        setTimeout(() => shell.showItemInFolder(packagePath), 500)
      } else {
        // 显示文件夹
        setTimeout(() => shell.openPath(packagePath), 500)
      }
    }
    if (buildConfig.notifyMe) {
      const msgBody = `用时${diffMinutes ? ' ' + diffMinutes + ' 分钟' : ''} ${diffSeconds} 秒`
      // 消息提醒
      const notice = new Notification({ title: '打包完成！', body: msgBody })
      notice.show()
    }
    return 'build Success!'
  },
  stopBuild: async (event, taskid) => {
    // 结束进程[id]

    // 清除进程[id]
  },
  // 查询当前是否有编译任务
  queryTask: async (event) => {
    apiSend.test()
  }

}

const apiSend = {
  buildInfo: (data) => {
    tabWinObj.currentView.webContents.send('listen:buildInfo', data)
  },
  percent: (num) => {
    tabWinObj.currentView.webContents.send('listen:percent', num)
  }
}

function execSingleBuild(ratio, cmd, dir) {
  // 占比70%
  return new Promise((resolve, reject) => {
    const task = childProcess.spawn('cmd', ['/c', cmd], { cwd: dir })
    task.stdout.on('data', (chunk) => {
      // console.log(iconv.decode(chunk, 'utf8'))
      apiSend.buildInfo(iconv.decode(chunk, 'utf8'))
    })
    let errdata = ''
    task.stderr.on('data', (chunk) => {
      // console.log('err ', iconv.decode(chunk, 'utf8'))
      errdata += iconv.decode(chunk, 'utf8')
      // apiSend.buildInfo(iconv.decode(chunk, 'utf8'))
    })
    task.on('close', (code) => {
      if (code) {
        apiSend.buildInfo(errdata)
        percent.set(0)
        reject()
      } else {
        percent.set(percent.get() + ratio * 0.7 * 100)
        resolve()
      }
    })
  })
}

function execSingleCopy(ratio, sourceDir, distDir) {
  // 占比10%
  return new Promise((resolve) => {
    let task = null
    if (sourceDir.includes('portal_nuxt') || sourceDir.includes('trusted_trade')) {
      task = childProcess.spawn('cmd', ['/c', `robocopy ${sourceDir}/.nuxt ${distDir}/.nuxt /mir /njh /ndl /nc /ns & robocopy ${sourceDir}/static ${distDir}/static /mir /njh /ndl /nc /ns`])
    } else {
      task = childProcess.spawn('cmd', ['/c', `robocopy ${sourceDir}/dist ${distDir}/dist /mir /njh /ndl /nc /ns`])
    }
    task.stdout.on('data', (chunk) => {
      // console.log(iconv.decode(chunk, 'gbk'))
      apiSend.buildInfo(iconv.decode(chunk, 'gbk'))
    })
    task.stderr.on('data', (chunk) => {

    })
    task.on('close', (code) => {
      percent.set(percent.get() + ratio * 0.1 * 100)
      resolve()
    })
  })
}

export const apiInvokeKey = Object.keys(apiInvoke) // ipcRender主动调用
export const apiSendKey = Object.keys(apiSend)   // ipcMain主动发送

export default function reactToApiInvoke(tabWin) {
  Object.entries(apiInvoke).forEach(([api, fn]) => {
    ipcMain.handle(`api:${api}`, fn)
  })
  tabWinObj = tabWin
}